package com.xuecheng.content.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.xuecheng.api.client.SearchClient;
import com.xuecheng.api.dto.CourseIndex;
import com.xuecheng.base.constant.CourseAuditStatusConstant;
import com.xuecheng.base.constant.CoursePublishStatusConstant;
import com.xuecheng.base.exception.CommonError;
import com.xuecheng.base.exception.XCPlusBaseException;
import com.xuecheng.content.exception.CourseNotAuditSuccessException;
import com.xuecheng.content.exception.CourseNotBelongException;
import com.xuecheng.content.exception.CourseNotExistOrNotSubmitException;
import com.xuecheng.content.exception.CourseNotPublishException;
import com.xuecheng.content.mapper.CoursePublishMapper;
import com.xuecheng.content.mapper.CoursePublishPreMapper;
import com.xuecheng.content.model.dto.CourseBaseInfoDTO;
import com.xuecheng.content.model.dto.CoursePreviewDTO;
import com.xuecheng.content.model.dto.TeachPlanDTO;
import com.xuecheng.content.model.po.CourseBase;
import com.xuecheng.content.model.po.CoursePublish;
import com.xuecheng.content.model.po.CoursePublishPre;
import com.xuecheng.content.model.po.CourseTeacher;
import com.xuecheng.content.service.ICourseBaseService;
import com.xuecheng.content.service.ICoursePublishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.message.sdk.constant.MqMessageTypeConstant;
import com.xuecheng.message.sdk.model.po.MqMessage;
import com.xuecheng.message.sdk.service.IMqMessageService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 课程发布 服务实现类
 * </p>
 *
 * @author 勾新杰
 * @since 2025-02-15
 */
@Service
@RequiredArgsConstructor
public class CoursePublishServiceImpl extends ServiceImpl<CoursePublishMapper, CoursePublish> implements ICoursePublishService {

    /**
     * 课程发布mapper
     */
    private final CoursePublishMapper coursePublishMapper;

    /**
     * 课程预发布mapper
     */
    private final CoursePublishPreMapper coursePublishPreMapper;

    /**
     * 课程基本信息mapper
     */
    private final ICourseBaseService courseBaseService;

    /**
     * 消息队列服务
     */
    private final IMqMessageService mqMessageService;

    /**
     * 搜索客户端
     */
    private final SearchClient searchClient;

    /**
     * 课程发布
     *
     * @param courseId 课程id
     */
    @Override
    @Transactional
    public void publish(Long courseId) {
        // 1. 在预发布表中查询该课程
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        // 1.1. 如果没查到，说明没提交审核或者不存在
        if (coursePublishPre == null) CourseNotExistOrNotSubmitException.cast();
        // 1.2. 如果查到，查看是否属于本机构的课程
        if (coursePublishPre.getCompanyId() != 1232141425L) CourseNotBelongException.cast(); // TODO 这里以后也需要改
        // 1.3. 如果查到，查看审核状态是否是审核通过
        CourseBase courseBase = courseBaseService.getById(courseId);
        if (!CourseAuditStatusConstant.PASSED.equals(courseBase.getAuditStatus()))
            CourseNotAuditSuccessException.cast();
        // 2. 复制课程预发布表的数据到课程发布表
        CoursePublish coursePublish = BeanUtil.copyProperties(coursePublishPre, CoursePublish.class);
        coursePublish.setCreateDate(LocalDateTime.now());
        coursePublish.setOnlineDate(LocalDateTime.now());
        coursePublish.setStatus(CoursePublishStatusConstant.PUBLISHED);
        CoursePublish select = coursePublishMapper.selectById(courseId);
        if (select == null) coursePublishMapper.insert(coursePublish);
        else {
            coursePublishMapper.updateById(coursePublish);
            coursePublishMapper.updateOfflineDate(courseId);
        }
        // 3. 删除课程预发布表数据
        coursePublishPreMapper.deleteById(courseId);
        // 4. 向消息队列表中插入消息（数据库）
        saveCoursePublishMessage(coursePublish);
        // 5. 设置课程基本表的发布状态为已发布
        courseBaseService.lambdaUpdate()
                .set(CourseBase::getStatus, CoursePublishStatusConstant.PUBLISHED)
                .set(CourseBase::getChangeDate, LocalDateTime.now())
                .eq(CourseBase::getId, courseId)
                .update();
    }

    /**
     * 向消息队列表中插入消息
     *
     * @param coursePublish 课程发布信息
     */
    private void saveCoursePublishMessage(CoursePublish coursePublish) {
        MqMessage mqMessage = mqMessageService.addMessage(MqMessageTypeConstant.MESSAGE_TYPE_COURSE_PUBLISH, String.valueOf(coursePublish.getId()), null, null);
        if (mqMessage == null) XCPlusBaseException.cast(CommonError.UNKNOWN_ERROR);
    }

    /**
     * 课程下线
     *
     * @param courseId 课程id
     */
    @Override
    @Transactional
    public void offline(Long courseId) {
        // 0. 合法性校验
        CoursePublish coursePublish = getById(courseId);
        if (coursePublish == null || CoursePublishStatusConstant.OFF_SHELF.equals(coursePublish.getStatus()))
            CourseNotPublishException.cast();
        if (coursePublish.getCompanyId() != 1232141425L)
            CourseNotBelongException.cast();
        // 1. 更新课程发布表
        this.lambdaUpdate()
                .set(CoursePublish::getOfflineDate, LocalDateTime.now())
                .set(CoursePublish::getStatus, CoursePublishStatusConstant.OFF_SHELF)
                .eq(CoursePublish::getId, courseId)
                .update();
        // 2. 更新课程基本表
        courseBaseService.lambdaUpdate()
                .set(CourseBase::getStatus, CoursePublishStatusConstant.OFF_SHELF)
                .set(CourseBase::getChangeDate, LocalDateTime.now())
                .eq(CourseBase::getId, courseId)
                .update();
        // 3. 更新索引库该课程的状态为下架
        searchClient.update(CourseIndex.builder()
                .id(courseId)
                .status(CoursePublishStatusConstant.OFF_SHELF)
                .build());
        // 那些永久或者确认长时间下架的课程，课程发布表并不会删除，而是设计标记，
        // 所以打算采用定时任务来删除minio中很久不用的静态文件、索引库中长时间下架的课程
    }

    /**
     * 查询下架两个月以上的课程
     *
     * @return List<CoursePublish>
     */
    @Override
    public List<CoursePublish> selectLongTimeOffline() {
        return coursePublishMapper.selectLongTimeOffline(CoursePublishStatusConstant.OFF_SHELF);
    }

    /**
     * 获取课程发布信息
     *
     * @param courseId 课程id
     * @return CoursePreviewDTO
     */
    @Override
    public CoursePreviewDTO getCoursePublishWhole(Long courseId) {
        CoursePublish coursePublish = getById(courseId);
        CourseBaseInfoDTO courseBaseInfoDTO = BeanUtil.copyProperties(coursePublish, CourseBaseInfoDTO.class);
        List<TeachPlanDTO> teachPlanDTOList = JSON.parseArray(coursePublish.getTeachplan(), TeachPlanDTO.class);
        List<CourseTeacher> courseTeacherList = JSON.parseArray(coursePublish.getTeachers(), CourseTeacher.class);
        return CoursePreviewDTO.builder()
                .courseBase(courseBaseInfoDTO)
                .teachplans(teachPlanDTOList)
                .teachers(courseTeacherList)
                .build();
    }
}
